package pyrachnid.ctrl;

import java.util.ArrayList;

import pyrachnid.ctrl.listener.listenerCell;
import pyrachnid.ctrl.listener.listenerFire;
import pyrachnid.ctrl.listener.listenerRobot;
import pyrachnid.ctrl.listener.listenerWind;
import pyrachnid.model.ground_model.Cell;
import pyrachnid.model.ground_model.Map;
import pyrachnid.model.robot_model.Manager;
import pyrachnid.model.robot_model.RobotType;
import pyrachnid.model.scenar_model.Scenario;
import pyrachnid.model.scenar_model.Statistics;
import pyrachnid.view.MainWindow;
import Event.Event;
import Event.Operation.AllocateRobot;
import Event.Operation.Extinguish;
import Event.Operation.LightFire;
import Event.Operation.Move;
import Event.Operation.ReachFireRobot;

public class Simulator {
	private Scenario _initialScenar;
	private Scenario _currentScenario;
	private MainWindow _mainWindow;
	private listenerCell _listenerCell;
	private listenerRobot _listenerRobot;
	private listenerFire _listenerFire;
	private listenerWind _listenerWind;
	private Statistics _currentStatistics; 
	private ArrayList<Event> _myArrayCellList;
	private ArrayList<Event> _myArrayRobotList;
	
	public Simulator() {

		// View
		_mainWindow = new MainWindow(this);		
		_currentStatistics = new Statistics();
	}
	
	public Scenario getSenario() {
		return _currentScenario;
	}
	
	public void setInitialScenar(Scenario scenar) {
		try {
			_initialScenar = scenar.clone();
		} catch (CloneNotSupportedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	/**
	 * Start simulation in the manager
	 */
	public void startSimu() {
		_mainWindow.start();
		Manager.getInstance().start();
	}
	
	/**
	 * Display statistic window
	 */
	public void displayStatsView()
	{
		_mainWindow.displayStatsWindow();
	}
	
	/** Robot type manager Window **/

	/**
	 * Display robot type manager window
	 */
	public void displayTypeRobotWindow() {
		_mainWindow.displayTypeRobotWindow();
	}
	
	/**
	 * Add default robot type to robot type list
	 * @return
	 */
	public void addRobotType() {
		_currentScenario.addRobotType(new RobotType());
	}
	
	/**
	 * Delete from robot type list at the selected index
	 * @param p_index Index of the type robot in list
	 * @return Status of removal request
	 */
	public boolean removeRobotType(int p_index) {
		return _currentScenario.removeRobotType(p_index);
	}
	
	/**
	 * Refresh robot type list
	 */
	public void refreshList() {
		_mainWindow.refreshList();
	}
	
	/** Simulation controls **/

	public void stopSimu() {
		_mainWindow.stop();
		Manager.getInstance().stop();
		saveEvent();
		
		try {
			_myArrayCellList = _currentScenario.getSerializeEventCell();
			_myArrayRobotList = _currentScenario.getSerializeEventRobot();
		} catch (Exception e) {
			// TODO Bloc catch auto-g�n�r�
			e.printStackTrace();
		}
	}

	public void createScenar() {
		this.initSimu();
		_mainWindow.createScenar();
		setInitialScenar(_currentScenario);
	}

	public void deleteScenar() {
		this.initSimu();
	}

	public void loadScenar(Scenario scenar) {
		_currentScenario = scenar;
		Manager manager = Manager.getInstance();
		manager.setMap(_currentScenario.getMap());
		manager.setRobot(_currentScenario.getRobotList());
		manager.setScenario(_currentScenario);
		this.initListener();
		_mainWindow.loadScenar(scenar);
		try {
			setInitialScenar(_currentScenario.clone());
		} catch (CloneNotSupportedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	public void reInit() {
		loadScenar(_initialScenar);
	} 
	
	private void initSimu() {
		// Scénario
		_currentScenario = new Scenario(this);		
		this.initListener();
	}
	
	public void initListener() {
		Map map = _currentScenario.getMap();
		// Listener
		_listenerCell = new listenerCell(this, _mainWindow);
		_listenerRobot = new listenerRobot(this, _mainWindow);
		_listenerFire = new listenerFire(this, _mainWindow);
		_listenerWind = new listenerWind(this, _mainWindow);
		
		if(map != null) {
			// Cell
			for(int i = 0; i < map.getXdimension(); i++) {
				for(int j = 0; j < map.getYdimension(); j++) {
					_currentScenario.getMap().getGround()[i][j].attach(_listenerCell);
				}
			}
			
			// Fire
			for(Cell cellInFire : map.getFires()) {
				cellInFire.getFire().attach(_listenerFire);
			}
			
			// Robot
			for(int i = 0; i < _currentScenario.getRobotList().size(); i++) {
				_currentScenario.getRobotList().get(i).attach(_listenerRobot);
			}
			
			// Wind
			_currentScenario.getWind().attach(_listenerWind);
		}
	}

	public MainWindow getMainWindow() {
		return _mainWindow;
	}
	
	private void saveEvent() {
		// S�rialisation de tous les �venements
		_currentScenario.serializeEvent();
	}
	
	@SuppressWarnings("unused")
	private ArrayList<Event> getSerializeRobot(){
		// Ce bloc permet de r�cup�rer la liste des events depuis les logs XML
		try {
			return _currentScenario.getSerializeEventRobot();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return new ArrayList<Event>();
	}
	
	@SuppressWarnings("unused")
	private ArrayList<Event> getSerializeWind(){
		// Ce bloc permet de r�cup�rer la liste des events depuis les logs XML
		try {
			return _currentScenario.getSerializeEventWind();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return new ArrayList<Event>();
	}
	
	@SuppressWarnings("unused")
	private ArrayList<Event> getSerializeCell(){
		// Ce bloc permet de r�cup�rer la liste des events depuis les logs XML
		try {
			return _currentScenario.getSerializeEventCell();
		} catch (Exception e) {
			// TODO Bloc catch auto-g�n�r�
			e.printStackTrace();
		}
		return new ArrayList<Event>();
	}
	
	//************** M�thodes Statistiques **************
	public String getTotalTime()
	{	
		//****************** Version avec les dates ************************
		//String firstDate = _myArrayCellList.get(0).getDate().toString();
		//String finalDate = _myArrayCellList.get(_myArrayCellList.size() - 1).getDate().toString();
		//String strDeb[] = firstDate.split(" ");
		//firstDate = strDeb[3].toString();
		//String strFin[]= finalDate.split(" ");
		//finalDate = strFin[3].toString();
		
		long firstDate = _myArrayCellList.get(0).getTime();
		long finalDate = _myArrayCellList.get(_myArrayCellList.size() - 1).getTime();
		String str[] = _currentStatistics.getTotalTime(firstDate, finalDate).split(":");
		return str[0].toString() + " heures " + str[1].toString() + " minutes " + str[2].toString() + " secondes";
	}
	
	public String getTempsExtinctionMoyen()
	{	
		int totalFeuEteint = 0;
		int sommeFeuEteint = 0;
		
		for(int i=0;i<_myArrayCellList.size();i++){

			if(_myArrayCellList.get(i).getOperation() instanceof Extinguish){
				sommeFeuEteint+=_myArrayCellList.get(i).getTime();
				totalFeuEteint+=1;
			}			
		}
		
		if(totalFeuEteint != 0)
			return ""+sommeFeuEteint/totalFeuEteint;
		
		return "0";		
	}
	
	public String getDistanceMoyenneRobotIncendie()
	{	
		ArrayList<Integer> listeInstance = new ArrayList<Integer>();
		AllocateRobot alloc;
		ReachFireRobot reach;
		int sommeCase = 0;
		int totalCase = 0;
		
		// On récupère tous les robots à qui on a allouer une cellule
		for(int i=0;i<_myArrayRobotList.size();i++){
			if(_myArrayRobotList.get(i).getOperation() instanceof AllocateRobot){
				alloc = (AllocateRobot)_myArrayRobotList.get(i).getOperation();
				if(!listeInstance.contains(alloc.getIdentifiant())){
					listeInstance.add(alloc.getIdentifiant());
					for(int j=0;j<_myArrayRobotList.size();j++){
							if(_myArrayRobotList.get(j).getOperation() instanceof Move){
								Move unMove = (Move)(_myArrayRobotList.get(j).getOperation());
								// On ne prends que les opperations Move d'un robot
								
								if(alloc.getIdentifiant() == unMove.getIdentifiant()){
									sommeCase+=1;								
								}
							}
							if(_myArrayRobotList.get(j).getOperation() instanceof ReachFireRobot){ 
								reach = (ReachFireRobot)_myArrayRobotList.get(j).getOperation();
								if(alloc.getIdentifiant() == reach.getIdentifiant()){
									
									totalCase+=1;
							}
						}
					}
				}
			}			
		}
			
		return ""+sommeCase/totalCase;		
	}
	
	public String getDistanceTotalRobotIncendie() 
    {     
        ArrayList<Integer> listeInstance = new ArrayList<Integer>(); 
        AllocateRobot alloc; 
        ReachFireRobot reach; 
        int sommeCase = 0; 
		int totalCase = 0; 
         
        // On récupère tous les robots à qui on a allouer une cellule 
        for(int i=0;i<_myArrayRobotList.size();i++){ 
            if(_myArrayRobotList.get(i).getOperation() instanceof AllocateRobot){ 
                alloc = (AllocateRobot)_myArrayRobotList.get(i).getOperation(); 
                if(!listeInstance.contains(alloc.getIdentifiant())){ 
                    listeInstance.add(alloc.getIdentifiant()); 
                    for(int j=0;j<_myArrayRobotList.size();j++){ 
                            if(_myArrayRobotList.get(j).getOperation() instanceof Move){ 
                                Move unMove = (Move)(_myArrayRobotList.get(j).getOperation()); 
                                // On ne prends que les opperations Move d'un robot 
                                 
                                if(alloc.getIdentifiant() == unMove.getIdentifiant()){ 
                                    sommeCase+=1;                                 
                                } 
                            } 
                            if(_myArrayRobotList.get(j).getOperation() instanceof ReachFireRobot){  
                                reach = (ReachFireRobot)_myArrayRobotList.get(j).getOperation(); 
                                if(alloc.getIdentifiant() == reach.getIdentifiant()){ 
                                     
                                    totalCase+=1; 
                            } 
                        } 
                    } 
                } 
            }             
        } 
             
        return ""+sommeCase;         
    } 
     
    
    public String getTempsMoyenRobotAvantAtteindreIncendie() 
    {     
        ArrayList<Integer> listeInstance = new ArrayList<Integer>(); 
        AllocateRobot alloc; 
        ReachFireRobot reach; 
        long sommeTime = 0; 
        long totalTime = 0;
        long timeDep, timeArr = 0;
        
        // On récupère tous les robots à qui on a allouer une cellule 
        for(int i=0;i<_myArrayRobotList.size();i++){ 
       
            if(_myArrayRobotList.get(i).getOperation() instanceof AllocateRobot){ 
                alloc = (AllocateRobot)_myArrayRobotList.get(i).getOperation();
                timeDep = _myArrayRobotList.get(i).getTime();
                
                if(!listeInstance.contains(alloc.getIdentifiant())){ 
                    listeInstance.add(alloc.getIdentifiant()); 
                    
                    for(int j=0;j<_myArrayRobotList.size();j++){ 
                        
                            if(_myArrayRobotList.get(j).getOperation() instanceof ReachFireRobot){  
                                reach = (ReachFireRobot)_myArrayRobotList.get(j).getOperation(); 
                                if(alloc.getIdentifiant() == reach.getIdentifiant()){ 
                                timeArr = _myArrayRobotList.get(j).getTime(); 
                                sommeTime += timeArr - timeDep;
                                totalTime += 1;
                            } 
                        } 
                    } 
                } 
            }             
        } 
        long total = (sommeTime/totalTime);
        return ""+total/1000;         
    } 
	
    @SuppressWarnings("null")
	public String getPourcentageIncendieEteintParRobot()
	{	
    	ArrayList<Integer> listeInstance = new ArrayList<Integer>();
   		AllocateRobot alloc;
   		ReachFireRobot reach;
   		long feuEteint = 0;
   		long feuEteintTotal = 0;
   		String result = "";
   		String robotType = "";
   		ArrayList<String> increment = new ArrayList<String>();
   		boolean passer = false;
   		
   		// On récupère tous les robots à qui on a allouer une cellule
   		for(int i=0;i<_myArrayRobotList.size();i++){
   			
   			if(_myArrayRobotList.get(i).getOperation() instanceof AllocateRobot){
   				alloc = (AllocateRobot)_myArrayRobotList.get(i).getOperation();
   				if(!listeInstance.contains(alloc.getIdentifiant())){
   					listeInstance.add(alloc.getIdentifiant());
   					feuEteint=0;
   					for(int j=0;j<_myArrayRobotList.size();j++){
   							if(_myArrayRobotList.get(j).getOperation() instanceof ReachFireRobot){ 
   								reach = (ReachFireRobot)_myArrayRobotList.get(j).getOperation();
   								if(alloc.getIdentifiant() == reach.getIdentifiant()){
   									robotType = reach.getRoboType();
   									feuEteint+=1;
   									feuEteintTotal+=1;
   							}
   						}
   					}
   					if (increment != null){
   						passer = false;
	   					for (int t=0; t<increment.size();t++){
	   						String inceremntValue[] = increment.get(t).split(":");
	   						if (inceremntValue[0].equals(robotType) && passer == false) {
	   							long lolo = Long.parseLong(inceremntValue[1]) + 1;
	   							result = result + robotType + " " + lolo + ":" + feuEteint + "-";
	   							increment.set(t, robotType + ":" + lolo);
	   							passer = true;
	   						}
	   					}
	   					if (passer == false) {
	   						result = result + robotType + " 1" + ":" + feuEteint + "-";
	   						increment.add(robotType + ":1");
	   					}
   					}
   					else{
   						result = result + robotType + " 1" + ":" + feuEteint + "-";
   						increment.add(robotType + ":1");
   					}
   				}
   			}			
   		}
   		
   		result = result + "/" + feuEteintTotal;
   		
   		//System.out.println(result);
   		return result;			
	}
    
    public String getPourcentageIncendieEteintParTypeRobot()
   	{	
   		ArrayList<Integer> listeInstance = new ArrayList<Integer>();
   		AllocateRobot alloc;
   		ReachFireRobot reach;
   		long feuEteint = 0;
   		long feuEteintTotal = 0;
   		String result = "";
   		String robotType = "";
   		
   		// On récupère tous les robots à qui on a allouer une cellule
   		for(int i=0;i<_myArrayRobotList.size();i++){
   			
   			if(_myArrayRobotList.get(i).getOperation() instanceof AllocateRobot){
   				alloc = (AllocateRobot)_myArrayRobotList.get(i).getOperation();
   				if(!listeInstance.contains(alloc.getIdentifiant())){
   					listeInstance.add(alloc.getIdentifiant());
   					feuEteint=0;
   					for(int j=0;j<_myArrayRobotList.size();j++){
   							if(_myArrayRobotList.get(j).getOperation() instanceof ReachFireRobot){ 
   								reach = (ReachFireRobot)_myArrayRobotList.get(j).getOperation();
   								if(alloc.getIdentifiant() == reach.getIdentifiant()){
   									robotType = reach.getRoboType();
   									feuEteint+=1;
   									feuEteintTotal+=1;
   							}
   						}
   					}
   					result = result + robotType + ":" + feuEteint + "-";
   				}
   			}			
   		}
   		
   		result = result + "/" + feuEteintTotal;
   		
   		//System.out.println(result);
   		return result;		
   	}
    
    public String getPourcentageCarteBrulee() 
    {     
    	long totalFeuEteint = 0; 
        long totalCase = (_currentScenario.getMap().getXdimension()*_currentScenario.getMap().getYdimension()); 
        for(int i=0;i<_myArrayCellList.size();i++){ 
        // Somme total de feux allumé
            if(_myArrayCellList.get(i).getOperation() instanceof LightFire){ 
                totalFeuEteint+=1;  
            }             
        } 
          
        if(totalFeuEteint != 0) {
        	float tmp = totalFeuEteint*100;
        	return ""+tmp/totalCase; 
        }
            
          
         return "0";      
    }
    
	//************** Fin M�thodes Statistiques **************
}